/*
 *  homedeoptW.c
 */

#include "syscall.h"

#define MAXCLERKS 5
#define MAXSTOCKBOYS 5
#define MAXAISLES 5
#define MAXSHELVES 10
#define MAXSHELFQUANTITY 30
#define MAXCARTSIZE 10

typedef enum 
{
	FALSE = 0, 
	TRUE = 1
} boolean;

typedef enum { 
	NONE,
	REPLENISHING
} shelfState;

typedef enum {
	RESTING,
	WORKING
} stockboyState;

typedef enum {
	VALID,
	INVALID
} shelfValidity;

typedef struct {
	int productID;
	int price;
} Product;

typedef struct {
	shelfState state; 
	int aisleNumber;
	int shelfItemType; 
	int shelfItemPrice;
	Product* products[MAXSHELFQUANTITY];
	int currentItemCount;
} Shelf;


// global lock to access global information
int globalInfoLock;
// To keep track of total customers served
int totalCustomersServed;
// Total money made from purchases - This figure is the manager's estimate during simulation
int storeTotal;


// Home depot's lock for each shelf
int shelfLocks[MAXSHELVES];
// Home depot's Products
Shelf shelves[MAXSHELVES];


// Clerk line lock ensures that only one instance can check/increment/decrement the line count at a time.
int clerkLineLock;
// for waking up sleeping customers in line
int clerkLineCV[MAXCLERKS];
// Condition variable for each clerk b/c each clerk has their own
// line. The customer must have a way to know whether the clerk
// is on break; 0 is working, 1 is on break
int clerkState[MAXCLERKS];
// Represents the line length for each clerk (each index)
int clerkLineLength[MAXCLERKS];


// for gaining control of a clerk
int clerkLocks[MAXCLERKS];
// for scanning goods
int clerkCV[MAXCLERKS];
// Shared variable for processing transaction
Product productToScan[MAXCLERKS]; 
// To let the clerk know whether customer puts last item
boolean productScanningFinished[MAXCLERKS];
// For clerks to tell customers how much they owe
int paymentTotalForCustomers[MAXCLERKS];


// Locks for cash register data
int cashRegisterLocks[MAXCLERKS];
// Condition vars for cash register
int cashRegisterCV[MAXCLERKS];
// Cash Register status
boolean cashRegisterFinishedStatus[MAXCLERKS];
// For transactions between the clerk & the cash register
Product cashRegisterCounter[MAXCLERKS];
// The total for each customer for a clerk and a cash register
int paymentTotal[MAXCLERKS];
// Total amount of money in sales for each register
int cashRegisterSales[MAXCLERKS];


// Lock for knowing which customer are currently being served - by clerk
int customerBeingServedLock;
int customerBeingServed[MAXCLERKS];
// Lock for knowing which customer are currently being helped - by stockboy
int customerBeingHelpedLock;
int customerBeingHelped[MAXSTOCKBOYS];


// Lock for changing aisle location of a stockboy
int stockboysStatusLock;
// for current aisle location, -1 means currently not in any aisle
int stockboysStatus[MAXSTOCKBOYS]; 


// Lock for the stockroom
int stockroomLock;



// Lock for stockboys
int stockboysLocks[MAXSTOCKBOYS];
// State of a stockboy: 0 is working, 1 is on break
int stockboysState[MAXSTOCKBOYS];
// Condition variable for a stockboy
int stockboysCV[MAXSTOCKBOYS];


// Lock that protects the checkoutAssistance button
int checkoutAssistanceLock;
// Button that is pushed when a customer sees that all clerks are ONBREAK.
// TRUE is need help, FALSE if no help needed
boolean checkoutAssistance;
// ConditionVar that will wake up customers when the checkout assistance request
// has been fulfilled
int checkoutAssistanceCV;


// Lock for button that clerk presses when he is overwhelmed with customers
int clerkNeedAssistanceButtonLock;
// false = clerk's line is less than 4, true = clerk's line is more than 4
boolean clerkNeedAssistanceButton;


// Lock for customer & manager to access this button
int customerAssistanceButtonLock;
// Customer presses on this button if no stockboys can be found
boolean customerAssistanceButton;
// CV for customers to wait on when the manager wakes up all stockboys
int customerAssistanceButtonCV;


// Locks for stockboy to help customers
int aisleHelpLocks[MAXAISLES];
// The customer line for stockboy's help for each aisle
int aisleHelpLine[MAXAISLES];
// Condition variables for stockboy's help for each aisle
int aisleCV[MAXAISLES];


// Lock for asking the location of a product from the stockboy
int stockboyProductToHelpLock;
// Customer tells his stockboy which product he is looking for
int stockboyProductToHelp[MAXSTOCKBOYS];


// Lock for giving an aisleNumber to the customer
int aisleNumberForCustomerLock;
// Stockboy tells the customer which aisle to go to
int aisleNumberForCustomer[MAXSTOCKBOYS];


void initializeGlobalVariables() {
	
	int j, k, m;
	
	globalInfoLock = CreateLock("globalInfoLock", sizeof("globalInfoLock"));
	totalCustomersServed = 0;
	storeTotal = 0;
	
	shelfLocks[0] = CreateLock("shelfLock0", sizeof("shelfLock0"));
	shelfLocks[1] = CreateLock("shelfLock1", sizeof("shelfLock1"));
	shelfLocks[2] = CreateLock("shelfLock2", sizeof("shelfLock2"));
	shelfLocks[3] = CreateLock("shelfLock3", sizeof("shelfLock3"));
	shelfLocks[4] = CreateLock("shelfLock4", sizeof("shelfLock4"));
	shelfLocks[5] = CreateLock("shelfLock5", sizeof("shelfLock5"));
	shelfLocks[6] = CreateLock("shelfLock6", sizeof("shelfLock6"));
	shelfLocks[7] = CreateLock("shelfLock7", sizeof("shelfLock7"));
	shelfLocks[8] = CreateLock("shelfLock8", sizeof("shelfLock8"));
	shelfLocks[9] = CreateLock("shelfLock9", sizeof("shelfLock9"));
	
	Write("SHELF LOCKS done.\n", sizeof("SHELF LOCKS done.\n"), ConsoleOutput);
	
	j = 0;
	k = 0;
	m = 0;
	for(j = 0 ; j < MAXSHELVES ; j++) 
	{
		shelves[j].state = NONE;
		shelves[j].aisleNumber = m;
		shelves[j].shelfItemType = j; 
		shelves[j].shelfItemPrice = 1;
		shelves[j].currentItemCount = MAXSHELFQUANTITY;
		for(k = 0 ; k < MAXSHELFQUANTITY ; k++) 
		{
			shelves[j].products[k]->productID = j;
			shelves[j].products[k]->price = shelves[j].shelfItemPrice;
		}
		
		if(j == 1 || j == 3 || j == 5 || j == 7)
		{
			m++;
		}
	}
	j = 0;
	k = 0;
	m = 0;

	clerkLineLock = CreateLock("clerkLineLock", sizeof("clerkLineLock"));
	
	clerkLineCV[0] = CreateCV("clerkLineCV0", sizeof("clerkLineCV0"));
	clerkLineCV[1] = CreateCV("clerkLineCV1", sizeof("clerkLineCV1"));
	clerkLineCV[2] = CreateCV("clerkLineCV2", sizeof("clerkLineCV2"));
	clerkLineCV[3] = CreateCV("clerkLineCV3", sizeof("clerkLineCV3"));
	clerkLineCV[4] = CreateCV("clerkLineCV4", sizeof("clerkLineCV4"));
	
	for(j = 0 ; j < MAXCLERKS ; j++) 
	{
		clerkState[j] = 0;
		clerkLineLength[j] = 0;
	}

	clerkLocks[0] = CreateLock("clerkLock0", sizeof("clerkLock0"));
	clerkLocks[1] = CreateLock("clerkLock1", sizeof("clerkLock1"));
	clerkLocks[2] = CreateLock("clerkLock2", sizeof("clerkLock2"));
	clerkLocks[3] = CreateLock("clerkLock3", sizeof("clerkLock3"));
	clerkLocks[4] = CreateLock("clerkLock4", sizeof("clerkLock4"));
	
	clerkCV[0] = CreateCV("clerkCV0", sizeof("clerkCV0"));
	clerkCV[1] = CreateCV("clerkCV1", sizeof("clerkCV1"));
	clerkCV[2] = CreateCV("clerkCV2", sizeof("clerkCV2"));
	clerkCV[3] = CreateCV("clerkCV3", sizeof("clerkCV3"));
	clerkCV[4] = CreateCV("clerkCV4", sizeof("clerkCV4"));
	
	for(j = 0 ; j < MAXCLERKS ; j++) 
	{
		productToScan[j].productID = 0;
		productToScan[j].price = 0;
		productScanningFinished[j] = FALSE;
		paymentTotalForCustomers[j] = 0;
	}
	
	cashRegisterLocks[0] = CreateLock("registerLock0", sizeof("registerLock0"));
	cashRegisterLocks[1] = CreateLock("registerLock1", sizeof("registerLock1"));
	cashRegisterLocks[2] = CreateLock("registerLock2", sizeof("registerLock2"));
	cashRegisterLocks[3] = CreateLock("registerLock3", sizeof("registerLock3"));
	cashRegisterLocks[4] = CreateLock("registerLock4", sizeof("registerLock4"));
	
	cashRegisterCV[0] = CreateCV("registerCV0", sizeof("registerCV0"));
	cashRegisterCV[1] = CreateCV("registerCV1", sizeof("registerCV1"));
	cashRegisterCV[2] = CreateCV("registerCV2", sizeof("registerCV2"));
	cashRegisterCV[3] = CreateCV("registerCV3", sizeof("registerCV3"));
	cashRegisterCV[4] = CreateCV("registerCV4", sizeof("registerCV4"));
	
	for(j = 0 ; j < MAXCLERKS ; j++) 
	{
		cashRegisterFinishedStatus[j] = FALSE;
		cashRegisterCounter[j].productID = 0;
		cashRegisterCounter[j].price = 0;
		paymentTotal[j] = 0;
		cashRegisterSales[j] = 0;
	}
	
	customerBeingServedLock = CreateLock("customerBeingServedLock", sizeof("customerBeingServedLock"));
	
	for(j = 0 ; j < MAXCLERKS ; j++) 
	{
		customerBeingServed[j] = 0;
	}
	
	customerBeingHelpedLock = CreateLock("customerBeingHelpedLock", sizeof("customerBeingHelpedLock"));
	
	for(j = 0 ; j < MAXSTOCKBOYS ; j++)
	{
		customerBeingHelped[j] = 0;
	}
	
	stockboysStatusLock = CreateLock("stockboysStatusLock", sizeof("stockboysStatusLock"));
	
	for(j = 0 ; j < MAXSTOCKBOYS ; j++) 
	{
		stockboysStatus[j] = -1
	}
	
	stockroomLock = CreateLock("stockroomLock", sizeof("stockroomLock"));	
	
	stockboysLocks[0] = CreateLock("stockboy0lock", sizeof("stockboy0lock"));
	stockboysLocks[1] = CreateLock("stockboy1lock", sizeof("stockboy1lock"));
	stockboysLocks[2] = CreateLock("stockboy2lock", sizeof("stockboy2lock"));
	stockboysLocks[3] = CreateLock("stockboy3lock", sizeof("stockboy3lock"));
	stockboysLocks[4] = CreateLock("stockboy4lock", sizeof("stockboy4lock"));
	
	for(j = 0 ; j < MAXSTOCKBOYS ; j++) 
	{
		stockboysState[j] = 0;
	}
	
	stockboysCV[0] = CreateCV("stockboy0CV", sizeof("stockboy0CV"));
	stockboysCV[1] = CreateCV("stockboy1CV", sizeof("stockboy1CV"));
	stockboysCV[2] = CreateCV("stockboy2CV", sizeof("stockboy2CV"));
	stockboysCV[3] = CreateCV("stockboy3CV", sizeof("stockboy3CV"));
	stockboysCV[4] = CreateCV("stockboy4CV", sizeof("stockboy4CV"));
	
	checkoutAssistanceLock = CreateLock("checkoutAssistanceLock", sizeof("checkoutAssistanceLock"));
	
	checkoutAssistance = FALSE;
	
	checkoutAssistanceCV = CreateCV("checkoutAssistanceCV", sizeof("checkoutAssistanceCV"));
	
	clerkNeedAssistanceButtonLock = CreateLock("clerkNeedAssistanceButtonLock", sizeof("clerkNeedAssistanceButtonLock"));
	
	clerkNeedAssistanceButton = FALSE;
	
	customerAssistanceButtonLock = CreateLock("customerAssistanceButtonLock", sizeof("customerAssistanceButtonLock"));
	
	customerAssistanceButton = FALSE;
	
	customerAssistanceButtonCV = CreateCV("customerAssistanceButtonCV", sizeof("customerAssistanceButtonCV"));
	
	aisleHelpLocks[0] = CreateLock("aisleHelpLocks0", sizeof("aisleHelpLocks0"));
	aisleHelpLocks[1] = CreateLock("aisleHelpLocks1", sizeof("aisleHelpLocks1"));
	aisleHelpLocks[2] = CreateLock("aisleHelpLocks2", sizeof("aisleHelpLocks2"));
	aisleHelpLocks[3] = CreateLock("aisleHelpLocks3", sizeof("aisleHelpLocks3"));
	aisleHelpLocks[4] = CreateLock("aisleHelpLocks4", sizeof("aisleHelpLocks4"));
	
	for(j = 0 ; j < MAXAISLES ; j++) 
	{
		aisleHelpLine[j] = 0;
	}
	
	aisleCV[0] = CreateCV("aisleCV0", sizeof("aisleCV0"));
	aisleCV[1] = CreateCV("aisleCV1", sizeof("aisleCV1"));
	aisleCV[2] = CreateCV("aisleCV2", sizeof("aisleCV2"));
	aisleCV[3] = CreateCV("aisleCV3", sizeof("aisleCV3"));
	aisleCV[4] = CreateCV("aisleCV4", sizeof("aisleCV4"));
	
	stockboyProductToHelpLock = CreateLock("stockboyProductToHelpLock", sizeof("stockboyProductToHelpLock"));
	
	for(j = 0 ; j < MAXSTOCKBOYS ; j++) 
	{
		stockboyProductToHelp[j] = -1;
	}
	
	aisleNumberForCustomerLock = CreateLock("aisleNumberForCustomerLock", sizeof("aisleNumberForCustomerLock"));
	
	for(j = 0 ; j < MAXSTOCKBOYS ; j++) 
	{
		aisleNumberForCustomer[j] = -1;
	}
	
}

int main() {
	
	initializeGlobalVariables();
	
	
	Exit(0);
}
